#ifndef xpack_utils_randomx
#define xpack_utils_randomx
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::utils_randomx::inc
#include"define/base_type.hpp"
#include"define/nan.hpp"
#include"instruction/ring_shift_left.hpp"
#include"instruction/time_stamp.hpp"
#include"macro/xexport.hpp"
#include"macro/xstruct.hpp"
#include"meta/is_same.hpp"
#pragma pop_macro("xuser")

namespace mixc::utils_randomx{
    constexpr u64 the_one     = 0x0fedcba987654321;

    xstruct(
        xname(randomx),
        xprif(m_x,  u64),
        xprif(m_y,  u64)
    )
        randomx(u64 x = inc::time_stamp(), u64 y = inc::time_stamp()):
            m_x(x + the_one), m_y(y - the_one){
        }

        template<class type_t>
        type_t get(){
            if constexpr (inc::is_same<type_t, f32>){
                union {
                    u64 u;
                    f32 candidate[2];
                } v;

                while(true){
                    if (v.u = this->random_core(); v.candidate[0] != inc::nan){
                        return v.candidate[0];
                    }
                    else if (v.candidate[1] != inc::nan){
                        return v.candidate[1];
                    }
                }
            }
            else if constexpr (inc::is_same<type_t, f64>){
                union {
                    u64 u;
                    f64 candidate;
                } v;

                while(true){
                    if (v.u = this->random_core(); v.candidate != inc::nan){
                        return v.candidate;
                    }
                }
            }
            else if constexpr (inc::is_same<type_t, bool>){
                return this->random_core() % 2 == 0;
            }
            else{
                return type_t(this->random_core());
            }
        }

    private:
        u64 random_core(){
            constexpr u64 change_period = 0x3f;

            // 由于线程会有不同的栈，所以这里可以补充随机性
            // 星星还是那个星星，月亮还是那个月亮，由于仰望者站的位置不同，所以领会的含义不同
            uxx dummy;
            uxx addition    = uxx(& dummy);

            // the_one 必须是一个奇数，当 inc::time_stamp() 总是偶数时，可以有如下规律
            // 偶数 inc::time_stamp() + 奇数 the_one 结果为奇数，
            // m_x 是偶数 m_x += 奇数 结果为 奇数
            // 下一轮 m_x += 奇数 -> 奇数 += 奇数 -> 偶数
            // 这样最初的 m_x 是奇数和偶数的概率刚好是一半
            //
            // 在嵌入式设备中，每次调用 inc::time_stamp() 的时间几乎固定，
            // 所以很有可能遇到每次调用都是偶数/奇数的情况，这种问题会导致随机源有一种偏向性，
            // 使得生成的伪随机数看起来不随机
            // 
            // 同时加法操作也有如下性质，任何整数 + 偶数 最终奇偶性不变
            // 此外嵌入式设备的起始 time_stamp 是一个较小的数值，对于一个 64bit 的数字来说高位有很多 0
            // 这也更可能让 ring_shift_left() 循环位移的结果是一个偶数，最后陷入了恶性循环，让数字不具有奇偶随机性
            if ((m_x & change_period) == 0){
                m_x        += inc::time_stamp() + the_one;
            }

            m_x            += inc::ring_shift_left(addition, uxx(m_y)) + the_one;
            m_x            += inc::ring_shift_left(m_y, uxx(m_x)) + the_one;
            m_y            += inc::ring_shift_left(m_x, uxx(m_y)) + the_one;

            // 只要没人知道它下一步会变成什么，那么它就是随机的。
            return m_y;
        }
    $
}

#endif

xexport(mixc::utils_randomx::randomx)
